package test.threads.queue.unstressed;

import java.util.Arrays;
import java.util.concurrent.ThreadFactory;

import net.jcip.annotations.Immutable;
import test.threads.ThreadAffinity.Core;

import static com.google.common.base.Preconditions.*;

/**
 * 1. Thread given meaning-full name, derived from factory name
 * 2. Thread attached to specific core
 * 3. Thread given highest possible priority {@link Thread#MAX_PRIORITY}
 *
 * @author cheremin
 * @since 26.10.11,  12:50
 */
public class BenchmarkThreadFactory implements ThreadFactory {

    private final Core[] cores;
    private final String name;

    private int index = 0;


    public BenchmarkThreadFactory( final Core core ) {
        this( "benchmarking-thread@" + core, core );
    }

    /*public BenchmarkThreadFactory( final String name ) {
        this( name, new Core[0] );
    }*/

    public BenchmarkThreadFactory( final String name,
                                   final Core... cores ) {
        checkArgument( name != null, "name can't be null" );
        checkArgument( cores != null, "cores can't be null" );
        this.cores = cores.clone();
        this.name = name;
    }

    @Override
    public synchronized Thread newThread( final Runnable r ) {
        try {
            final String threadName = formatThreadName();

            if ( cores.length > 0 ) {
                final int idx = index % cores.length;
                final Core core = cores[idx];

                final Thread thread = new Thread( new Runnable() {
                    @Override
                    public void run() {
                        setupCurrentThreadAsBenchmarking( core );

                        r.run();
                    }
                }, threadName );

                return thread;
            } else {
                final Thread thread = new Thread( r, threadName );
                thread.setPriority( Thread.MAX_PRIORITY );
                return thread;
            }
        } finally {
            index++;
        }
    }

    private String formatThreadName() {
        return name + "#" + index;
    }

    public static void setupCurrentThreadAsBenchmarking( final Core core ) {
        Thread.currentThread().setPriority( Thread.MAX_PRIORITY );
        try {
            core.attachTo();
        } catch ( Exception e ) {
            System.err.printf( "Can't set affinity: %s\n", e.getMessage() );
        }
    }
}
